# =============================================================================
#
#  FILE:
#    CodesizeElfParser.awk
#
#  RELATED FILES:
#    TLawk.awk (library)
#
#  DESCRIPTION:
#    Template of a Codesize parser for text files created by the readelf GNU utility.
#    Codesize information (code size of functions in each module, RAM and ROM
#    consumption) is generated to stdout.
#    AWK code for use with GNU AWK Vs 2.1.5
#    usage: tlawk.exe -v cmd=$(F_CMD) -f tlawk.awk -f CodesizeElfParser.awk >> $(F_CSI)
#
#  REMARKS:
#    The $(F_CMD) file contains line-by-line the following arguments:
#       - used microcontroller
#       - used compiler
#       - executable ELF file
#       - list of object ELF files, each file in a new line
#
#  AUTHOR(S):
#    I. Karwat
#
#  Copyright (c) 2006 dSPACE GmbH, GERMANY
#
#  $Workfile: CodesizeElfParser.awk $ $Revision: 1.4 $ $Date: 2007/06/15 10:38:53GMT+01:00 $ $Author: FrankL $
# =============================================================================

# ------------------------------------------------------------------------------
# S T A R T  O F  B E G I N  B L O C K
# ------------------------------------------------------------------------------

BEGIN {

    # get the readelf executable
    READELF = "readelf.exe";

    # initialize the variables ARGC and ARGV
    ARGC = 1;
    line = 1;

    # get input arguments passed in command file
    while(getline < cmd > 0)
    {
        # printf("%s\n", $1);

        # work on the microcontroller name
        if(line == 1)
        {
            MCU = toupper($1);
        }
        # work on the compiler name
        else if(line == 2)
        {
            COMPILER = toupper($1);
        }
        # work on the ELF executable file
        else if(line == 3)
        {
            readelfcmd = READELF " -h -S -s -W " $1 " > " $1 ".txt";
            if(system(readelfcmd) == 0)
            {
                # printf("OK: %s\n", readelfcmd);
            }
            else
            {
                printf("ERROR in CodesizeElfParser.awk executing:\n%s\n", readelfcmd);
            }
            ARGV[ARGC] = $1 ".txt";
            ARGC++;
        }
        # work on the ELF object files
        else
        {
            number_of_modules++;
            array_size = split($1,array, "\\");
            gsub(/[\.][A-Za-z]*/, "", array[array_size]);  # remove file extension
            modules_array[number_of_modules] = tolower(array[array_size]);
            readelfcmd = READELF " -s -W " $1 " > " $1 ".txt";
            if(system(readelfcmd) == 0)
            {
                # printf("OK: %s\n", readelfcmd);
            }
            else
            {
                printf("ERROR in CodesizeElfParser.awk executing the command:\n%s\n", readelfcmd);
            }
            ARGV[ARGC] = $1 ".txt";
            ARGC++;
        }
        line++;
    }

}

# ------------------------------------------------------------------------------
# E N D  O F  B E G I N  B L O C K
# ------------------------------------------------------------------------------


# ------------------------------------------------------------------------------
# INITIALIZE STATE VARIABLES
# ------------------------------------------------------------------------------

FNR == 1 {
    search_final_elf = 0;
    search_section_headers = 0;
    search_symbol_table = 0;
}

$0 ~ "^ELF Header:" {
    search_final_elf = 1;
}

$0 ~ "^Section Headers:" {
    search_section_headers = 1;
    next;
}

$0 ~ "^Key to Flags:" {
    search_section_headers = 0;
}

$0 ~ "^Symbol table" {
    search_symbol_table = 1;
    next;
}


# ------------------------------------------------------------------------------
# PARSE FUNCTION SYMBOLS FROM THE ELF EXECUTABLE TXT FILE
# ------------------------------------------------------------------------------
search_symbol_table == 1 && search_final_elf == 1 {

    if( ($4 == "FUNC") && (($5 == "GLOBAL") || ($5 == "LOCAL")) )
    {
        # printf("Found symbol: %s\n", $8);
        exe_number_of_symbols++;
        exe_symbol_name_tbl[exe_number_of_symbols]          = $8;
        exe_symbol_name_tbl_fcn_size[exe_number_of_symbols] = $3;
    }
}

# ------------------------------------------------------------------------------
# PARSE FUNCTION SYMBOLS FROM THE ELF OBJECTS TXT FILES
# ------------------------------------------------------------------------------
search_symbol_table == 1 && search_final_elf == 0 {

    if( ($4 == "FUNC") && (($5 == "GLOBAL") || ($5 == "LOCAL")) )
    {
        gsub(/[\.][A-Za-z]*/, "", FILENAME);  # remove file extension
        array_size = split(FILENAME, array, "\\");
        # printf("Found symbol: %s\n", $8);
        obj_number_of_symbols++;
        obj_symbol_name_tbl[obj_number_of_symbols]         = $8;
        obj_symbol_module_name_tbl[obj_number_of_symbols]  = array[array_size];
    }
}


# ------------------------------------------------------------------------------
# PARSE SECTIONS FROM THE ELF EXECUTABLE TXT FILE
# ------------------------------------------------------------------------------
search_final_elf == 1 && search_section_headers == 1 {

    # skip
    # [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
    if( ($2 == "Name") && ($3 == "Type") )
    {
        next;
    }
    # trigger on
    # [ 6] .text             PROGBITS        000807b0 0008b0 002898 00  AX  0   0  8
    if( ($1 ~ "^\[") && (($1 ~ "([0-9])\]$") || ($2 ~ "([0-9])\]$")) )
    {
        gsub("\[ ", "[", $0);
        split($0, array);

        # printf("Found section: %s with the size %s\n", array[2], array[6]);
        AssignSectionSize(array[2], array[6]);
    }
}


# -----------------------------------------------------------------------------
# S T A R T  O F  E N D  B L O C K
# -----------------------------------------------------------------------------

END {

    #
    # From all the function symbols found in the executable ELF file take only these
    # which were also found in the requested object ELF file modules
    #
    for (i = 1; i <= exe_number_of_symbols; i++)
    {
        for(j = 1; j <= obj_number_of_symbols; j++)
        {
            if(exe_symbol_name_tbl[i] == obj_symbol_name_tbl[j])
            {
                number_of_symbols++;
                symbol_name_tbl[number_of_symbols]          = exe_symbol_name_tbl[i];
                symbol_module_name_tbl[number_of_symbols]   = obj_symbol_module_name_tbl[j];
                symbol_name_tbl_fcn_size[number_of_symbols] = exe_symbol_name_tbl_fcn_size[i];
            }
        }
    }

    #
    # Module-by-module, print functions and their code sizes
    #
    for(i = 1; i <= number_of_modules; i++)
    {
        printf("\n*******************************************************************\n");
        printf("*****  Summary for module: %s\n", modules_array[i]);
        printf("*******************************************************************\n");
        printf("    Functions                                      [bytes]\n");
        printf("-------------------------------------------------------------------\n");

        for (j = 1; j <= number_of_symbols; j++)
        {
            if(tolower(modules_array[i]) == tolower(symbol_module_name_tbl[j]))
            {
                prefix = GetSymbolPrefix();

                if(prefix != "")
                {
                    gsub("^" prefix, "", symbol_name_tbl[j]); # remove prefix
                }
                printf("    %-40s   %10s\n", symbol_name_tbl[j], symbol_name_tbl_fcn_size[j]);
            }
        }
    }

    #
    # Print total summary information
    #
    printf("\n\n");
    printf("*******************************************************************\n");
    printf("*****  Model summary                               [bytes]\n");
    printf("*******************************************************************\n");
    printf("    RAM                                      = %10s\n", AssignRamSize());
    printf("    ROM without libraries                    = %10s\n", AssignRomSize() - AssignLibSize());
    printf("    ROM with libraries                       = %10s\n", AssignRomSize());

}

# ------------------------------------------------------------------------------
# E N D  O F  E N D  B L O C K
# ------------------------------------------------------------------------------



#/******************************************************************************
#*
#* FUNCTION: GetSymbolPrefix()
#*
#* DESCRIPTION:
#*   Tells the caller a function symbol names prefix.
#*
#* PARAMETERS:
#*
#* RETURNS:
#*          prefix
#*
#* NOTE:
#*   It can be configured for particular microcontroller and compiler.
#*
#******************************************************************************/
function GetSymbolPrefix()
{
    if( (MCU ~ "^V850") )
    {
        if( (COMPILER ~ "^GHS") || (COMPILER ~ "^GNU") || (COMPILER ~ "^NEC") )
        {
            return "_";
        }
    }

    if( (MCU ~ "^SH") )
    {
        if( (COMPILER ~ "^HIT") )
        {
            return "_";
        }
    }

    if( (MCU ~ "^56F83") )
    {
        if( (COMPILER ~ "^METROWERKS") )
        {
            return "F";
        }
    }

    if( (MCU ~ "^MPC") || (MCU ~ "^PPC") )
    {
        if( (COMPILER ~ "^GHS") || (COMPILER ~ "^GNU") || (COMPILER ~ "^DIAB") || (COMPILER ~ "^METROWERKS") || (COMPILER ~ "^MRI") )
        {
            return "";
        }
    }

    if( (MCU ~ "^TRICORE") )
    {
        if( (COMPILER ~ "^TASK2") || (COMPILER ~ "^GNU") )
        {
            return "";
        }
    }

    if( (MCU ~ "^HCS12") )
    {
        if( (COMPILER ~ "^METROWERKS") )
        {
            return "";
        }
    }

    return "_";
}

#/******************************************************************************
#*
#* FUNCTION: AssignSectionSize()
#*
#* DESCRIPTION:
#*   Assigns sizes in bytes for memory sections.
#*
#* PARAMETERS:
#*          SectionName
#*          SectionSize
#*
#* RETURNS:
#*
#* NOTE:
#*   It can be configured for particular microcontroller and compiler.
#*
#******************************************************************************/
function AssignSectionSize(SectionName, SectionSize)
{
    if((SectionName == ".text") || (SectionName ~ "^\.text\."))
    {
        text += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == "P")
    {
        P += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == "D")
    {
        D += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == "C")
    {
        C += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == "NON_BANKED")
    {
        non_banked += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".const")
    {
        const += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == "initdat")
    {
        initdat += F__HEX2INT_NH(SectionSize)
    }
    else if((SectionName == ".data") || (SectionName ~ "^\.data\."))
    {
        data += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".sdata2")
    {
        sdata2 += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".sdata")
    {
        sdata += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".tdata")
    {
        tdata += F__HEX2INT_NH(SectionSize)
    }
    else if((SectionName == ".zdata") || (SectionName ~ "^\.zdata\."))
    {
        zdata += F__HEX2INT_NH(SectionSize)
    }
    else if((SectionName == ".rodata") || (SectionName ~ "^\.rodata\."))
    {
        rodata += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".rosdata")
    {
        rosdata += F__HEX2INT_NH(SectionSize)
    }
    else if((SectionName == ".rozdata") || (SectionName ~ "^\.zrodata\."))
    {
        rozdata += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".robase")
    {
        robase += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".sdabase")
    {
        sdabase += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".common")
    {
        common += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == "B")
    {
        B += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == "R")
    {
        R += F__HEX2INT_NH(SectionSize)
    }
    else if((SectionName == ".bss") || (SectionName ~ "^\.bss\."))
    {
        bss += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".sbss")
    {
        sbss += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".sbss2")
    {
        sbss2 += F__HEX2INT_NH(SectionSize)
    }
    else if((SectionName == ".zbss") || (SectionName ~ "^\.zbss\."))
    {
        zbss += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".callt_data")
    {
        callt_data += F__HEX2INT_NH(SectionSize)
    }
    else if(SectionName == ".callt_text")
    {
        callt_text += F__HEX2INT_NH(SectionSize)
    }
}


#/******************************************************************************
#*
#* FUNCTION: AssignRomSize()
#*
#* DESCRIPTION:
#*   Returns the total ROM size.
#*
#* PARAMETERS:
#*
#* RETURNS:
#*          total ROM size
#*
#* NOTE:
#*   It can be configured for particular microcontroller and compiler.
#*
#******************************************************************************/
function AssignRomSize()
{
    return callt_text + callt_data + rodata + rosdata + rozdata + robase + text + const + non_banked + sdata2 + initdat + data + sdata + tdata + zdata + P + D + R + C;
}


#/******************************************************************************
#*
#* FUNCTION: AssignRamSize()
#*
#* DESCRIPTION:
#*   Returns the total RAM size.
#*
#* PARAMETERS:
#*
#* RETURNS:
#*          total RAM size
#*
#* NOTE:
#*   It can be configured for particular microcontroller and compiler.
#*
#******************************************************************************/
function AssignRamSize()
{
    return data + sdata + tdata + zdata + common + bss + sbss + sbss2 + zbss + sdabase + B + R;
}


#/******************************************************************************
#*
#* FUNCTION: AssignLibSize()
#*
#* DESCRIPTION:
#*   Returns the total libraries' size.
#*
#* PARAMETERS:
#*
#* RETURNS:
#*          total libraries' size
#*
#* NOTE:
#*   Currently not determined.
#*
#******************************************************************************/
function AssignLibSize()
{
    return 0;
}


# END OF FILE
